@sapphire/utilities
Common JavaScript utilities for the Sapphire Community.
Table of Contents
Description
We often have a need for a function or type augmentation and having to include it in every repo is a huge drag. To solve this problem there are dozens upon dozens of packages on NPM, but we cannot maintain those in case of issues and a lot of them are poorly written or under-optimised. Our solution is to provide @sapphire/utilities, which is the only package you'll likely need to cover your day-to-day needs.
Features
- Written in TypeScript
- Bundled with esbuild so it can be used in NodeJS and browsers
- Offers CommonJS, ESM and UMD bundles
- Fully tested
Installation
You can use the following command to install this package, or replace npm install
with your package manager of choice.
npm install @sapphire/utilities
Usage
You can import individual utility function from subpath like: @sapphire/utility/isFunction or the entire library.
import { isFunction } from '@sapphire/utilities/isFunction';
import { isFunction } from '@sapphire/utilities';
Note: For typescript users, subpath import are only supported in --moduleResolution node16
and --moduleResolution nodenext
. More information can be found in this issue on the microsoft/TypeScript repository.
Note: While this section uses require
, the imports match 1:1 with ESM imports. For example const { arrayStrictEquals } = require('@sapphire/utilities')
equals import { arrayStrictEquals } from '@sapphire/utilities'
.
Javascript Utilities
arrayStrictEquals
Compares if two arrays are strictly equal.
arrayStrictEquals([1, 2, 3], [1, 2, 3]);
arrayStrictEquals([1, 2, 3], [1, 2, 3, 4]);
arrayStrictEquals([1, 2, 3], [1, 2, 4]);
chunk
Splits up an array into chunks.
chunk([1, 2, 3, 4, 5], 2);
chunk([1, 2, 3, 4, 5], 3);
classExtends
Checks whether or not the value class extends the base class.
class A {}
class B extends A {}
classExtends(A, B);
classExtends(B, A);
codeBlock
Wraps text in a markdown codeblock with a language indicator for syntax highlighting.
codeBlock('js', 'const value = "Hello World!";');
cutText
Split a text by its latest space character in a range from the character 0 to the selected one.
cutText('Lorem Ipsum', 9);
deepClone
Deep clones an object.
const obj = { a: 1, b: { c: 2 } };
const clone = deepClone(obj);
filterNullAndUndefined
Checks whether a value is not null
nor undefined
. This can be used in Array#filter
to remove null
and undefined
from the array type
const someArray = ['one', 'two', undefined, null, 'five'];
const filteredArray = someArray.filter(filterNullAndUndefined);
filterNullAndUndefinedAndEmpty
Checks whether a value is not null
, undefined
, or ''
(empty string). This can be used in Array#filter
to remove null
, undefined
, and ''
from the array type
const someArray = [1, 2, undefined, null, ''];
const filteredArray = someArray.filter(filterNullAndUndefinedAndEmpty);
filterNullAndUndefinedAndZero
Checks whether a value is not null
, undefined
, or 0
. This can be used in Array#filter
to remove null
, undefined
, and 0
from the array type
const someArray = ['one', 'two', undefined, null, 0];
const filteredArray = someArray.filter(filterNullAndUndefinedAndZero);
getDeepObjectKeys
Returns an array of all the keys of an object, including the keys of nested objects.
const obj = { a: 1, b: { c: 2 }, d: [{ e: 3 }] };
getDeepObjectKeys(obj);
getDeepObjectKeys(obj, { arrayKeysIndexStyle: 'braces' });
getDeepObjectKeys(obj, { arrayKeysIndexStyle: 'braces-with-dot' });
getDeepObjectKeys(obj, { arrayKeysIndexStyle: 'dotted' });
hasAtLeastOneKeyInMap
Checks whether a map has at least one of an array of keys.
const map = new Map([
['a', 1],
['b', 2],
['c', 3]
]);
hasAtLeastOneKeyInMap(map, ['a', 'd']);
hasAtLeastOneKeyInMap(map, ['d', 'e']);
inlineCodeBlock
Wraps text in a markdown inline codeblock.
inlineCodeBlock('const value = "Hello World!";');
isClass
Verifies if the input is a class constructor.
class A {}
isClass(A);
isClass(function () {});
isFunction
Verifies if the input is a function.
isFunction(function () {});
isFunction('foo');
isNullOrUndefined
Checks whether a value is null
or undefined
.
isNullOrUndefined(null);
isNullOrUndefined(undefined);
isNullOrUndefined(1);
isNullOrUndefinedOrEmpty
Checks whether a value is null
, undefined
, or ''
(empty string).
isNullOrUndefinedOrEmpty(null);
isNullOrUndefinedOrEmpty(undefined);
isNullOrUndefinedOrEmpty('');
isNullOrUndefinedOrEmpty(1);
isNullOrUndefinedOrZero
Checks whether a value is null
, undefined
, or 0
.
isNullOrUndefinedOrZero(null);
isNullOrUndefinedOrZero(undefined);
isNullOrUndefinedOrZero(0);
isNullOrUndefinedOrZero(1);
isNumber
Verifies if the input is a number.
isNumber(1);
isNumber('1');
isObject
Verifies if the input is an object.
isObject({});
isObject([]);
isObject('foo');
isPrimitive
Verifies if the input is a primitive.
isPrimitive(1);
isPrimitive('1');
isPrimitive({});
isThenable
Verifies if an object is a promise.
isThenable({});
isThenable(Promise.resolve());
lazy
Lazily creates a constant or load a module and caches it internally.
let timesCalled = 0;
const lazyValue = lazy(() => {
timesCalled++;
return 'foo';
});
lazyValue();
lazyValue();
timesCalled;
makeObject
Turn a dotted path into a json object.
makeObject('a.b.c', 1);
mergeDefault
Deep merges two objects. Properties from the second parameter are applied to the first.
const base = { a: 1, b: { c: 2 } };
const overwritten = { b: { d: 3 } };
mergeDefault(base, overwritten);
overwritten;
mergeObjects
Merges two objects.
const source = { a: 1, b: 2 };
const target = { c: 4 };
mergeObjects(source, target);
target;
noop
A no-operation function.
noop();
Promise.reject().catch(noop);
objectToTuples
Converts an object to a tuple with string paths.
const obj = { a: 1, b: { c: 2 } };
objectToTuples(obj);
partition
Partitions an array into a tuple of two arrays, where one array contains all elements that satisfies the predicate, and the other contains all elements that do not satisfy the predicate.
const arr = [1, 2, 3, 4, 5];
const [evens, odds] = partition(arr, (n) => n % 2 === 0);
evens;
odds;
pickRandom
Picks a random element from an array.
const arr = [1, 2, 3, 4, 5];
pickRandom(arr);
range
Get an array of numbers with the selected range, considering a specified step.
range(1, 4, 1);
range(1, 4, 2);
range(4, 1, -1);
range(4, 1, -2);
regExpEsc
Cleans a string from regex injection by escaping special characters.
regExpEsc('foo.bar?');
roundNumber
Properly rounds up or down a number. Also supports strings using an exponent to indicate large or small numbers.
roundNumber(1.9134658034);
roundNumber(1.9134658034, 2);
roundNumber('10e-5');
sleep
/ sleepSync
Sleeps for the specified number of milliseconds.
await sleep(1000);
sleepSync(1000);
splitText
Split a string by its latest space character in a range from the character 0 to the selected one.
splitText('Hello All People!', 8);
splitText('Hello All People!', 10);
throttle
Creates a throttled function that only invokes a function at most once per every x milliseconds. The throttled function comes with a flush method to reset the last time the throttled function was invoked.
const throttled = throttle(() => console.log('throttled'), 1000);
throttled();
throttled();
throttled.flush();
throttled();
toTitleCase
Converts a string to Title Case. This is designed to also ensure common Discord PascalCased strings are put in their TitleCase variants.
toTitleCase('foo bar');
toTitleCase('textchannel');
toTitleCase('onetwo three', { onetwo: 'OneTwo' });
tryParseJSON
Tries to parse a string as JSON.
tryParseJSON('{"foo": "bar"}');
tryParseJSON('{"foo": "bar"' );
tryParseURL
Tries to parse a string as a URL.
tryParseURL('https://google.com');
tryParseURL('hello there :)');
Typescript Utilities
A subset of our utilities are intended specifically for typescript users.
Functions
cast
Casts any value to T
. Note that this function is not type-safe, and may cause runtime errors if used incorrectly.
const value = cast<string>(1);
objectEntries
A strongly-typed alternative to Object.entries
.
const obj = { a: 1, b: 2 } as const;
const native = Object.entries(obj);
const strict = objectEntries(obj);
objectKeys
A strongly-typed alternative to Object.keys
.
const obj = { a: 1, b: 2 } as const;
const native = Object.keys(obj);
const strict = objectKeys(obj);
objectValues
A strongly-typed alternative to Object.values
.
const obj = { a: 1, b: 2 } as const;
const native = Object.values(obj);
const strict = objectValues(obj);
Types
Primitive
A union of all primitive types.
declare const primitive: Primitive;
Builtin
A union of all builtin types.
declare const builtin: Builtin;
DeepReadonly
Makes all properties in T
readonly recursively.
type Foo = Set<{ bar?: ['foo', { hello: 'world' }] }>;
declare const foo: DeepReadonly<Foo>;
DeepRequired
Makes all properties in T
required recursively.
type Foo = Set<{ bar?: Promise<{ baz?: string }>[] }>;
declare const foo: DeepRequired<Foo>;
RequiredExcept
Makes all properties in T
required except for the ones specified in K
.
interface Foo {
bar?: string;
baz?: number;
}
declare const foo: RequiredExcept<Foo, 'bar'>;
PartialRequired
Makes all properties in T
that are assignable to K
required.
interface Foo {
bar?: string;
baz?: number;
}
declare const foo: PartialRequired<Foo, 'bar'>;
ArgumentTypes
Extracts the argument types of a function type.
type Foo = (bar: string, baz: number) => void;
declare const foo: ArgumentTypes<Foo>;
Arr
A type that represents a readonly array of any
.
declare const arr: Arr;
Ctor
A constructor with parameters.
declare const foo: Ctor;
declare const bar: Ctor<[string, number], SomeClass>;
AbstractCtor
An abstract constructor with parameters.
declare const foo: AbstractCtor;
declare const bar: AbstractCtor<[string, number], SomeClass>;
Constructor
A constructor without parameters.
declare const foo: Constructor;
declare const bar: Constructor<SomeClass>;
AbstractConstructor
An abstract constructor without parameters.
declare const foo: AbstractConstructor;
declare const bar: AbstractConstructor<SomeClass>;
FirstArgument
Extracts the first argument of a function type.
type Foo = (bar: string, baz: number) => void;
declare const foo: FirstArgument<Foo>;
SecondArgument
Extracts the second argument of a function type.
type Foo = (bar: string, baz: number) => void;
declare const foo: SecondArgument<Foo>;
Awaitable
A type that represents a value or a promise of a value. Useful for functions that can accept both promises and non-promises.
declare const foo: Awaitable<string>;
Nullish
A type that represents null
or undefined
.
declare const foo: Nullish;
NonNullableProperties
Removes all properties of T
that are not null
or undefined
.
interface Foo {
foo: null;
bar: undefined;
baz: boolean;
}
declare const foo: NonNullableProperties<Foo>;
NonNullObject
(deprecated)
A type that represents an object that is not null
or undefined
.
const foo: NonNullObject = {};
const bar: NonNullObject = null;
const baz: NonNullObject = undefined;
AnyObject
(deprecated)
An object that can have any structure. Similar to NonNullObject
, and to be used as an alternative if the aforementioned type leads to unexpected behaviors.
const foo: AnyObject = {};
const bar: AnyObject = null;
const baz: AnyObject = undefined;
PrettifyObject
An utility type that fuses intersections of objects.
type Objects = {
foo: string;
bar: number;
} & {
hello: boolean;
world: bigint;
};
type PrettyObjects = PrettifyObject<Objects>;
PickByValue
Picks keys from T
who's values are assignable to V
.
interface Foo {
foo: string;
bar: number;
baz: boolean;
}
declare const foo: PickByValue<Foo, string | number>;
Mutable
Makes all properties in T
mutable.
interface Foo {
readonly bar: string;
readonly baz: readonly number][];
}
declare const foo: Mutable<Foo>;
StrictRequired
Makes all properties in T
strictly required by removing undefined
and null
from value types.
interface Foo {
bar: string | undefined;
baz?: number | null;
}
declare const foo: StrictRequired<Foo>;
ArrayElementType
Gets a union type of all the keys that are in an array.
const sample = [1, 2, '3', true];
declare const foo: ArrayElementType<typeof sample>;
Buy us some doughnuts
Sapphire Community is and always will be open source, even if we don't get donations. That being said, we know there are amazing people who may still want to donate just to show their appreciation. Thank you very much in advance!
We accept donations through Open Collective, Ko-fi, Paypal, Patreon and GitHub Sponsorships. You can use the buttons below to donate through your method of choice.
Contributors
Please make sure to read the Contributing Guide before making a pull request.
Thank you to all the people who already contributed to Sapphire!